package com.proxyforgame.tetris.view;

import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import javax.swing.event.ChangeEvent;
import com.proxyforgame.tetris.model.BoardChangeListener;
import com.proxyforgame.tetris.model.Figure.Cell;
import com.proxyforgame.tetris.model.ScoreChangeListener;
import com.proxyforgame.tetris.model.TetrisGame;

public class TetrisView extends JPanel implements LayoutManager {

	private static final long	serialVersionUID	= 5839368311361333192L;

	private TetrisGame			game;
	private TetrisComponent		view				= null;
	private TetrisScorePanel	score				= null;
	private int					cellSize			= 8;
	private Color[]				colors				= new Color[] {Color.BLACK, Color.YELLOW, Color.MAGENTA, Color.BLUE, Color.GREEN, Color.LIGHT_GRAY, Color.CYAN, Color.RED};
	private Color				bgHL				= new Color(32, 32, 32);

	public TetrisView(TetrisGame game) {
		setLayout(new BorderLayout());
		setFocusable(true);

		this.game = game;
		view = new TetrisComponent();
		score = new TetrisScorePanel();
		JPanel p = new JPanel();
		p.setDoubleBuffered(false);
		p.setLayout(this);
		p.add(view);
		add(p);
		add(score, BorderLayout.EAST);

		game.addBoardChangeListener(new BoardChangeListener() {
			@Override
			public void stateChanged(ChangeEvent e) {
				view.repaint();
			}
		});
		addKeyListener(new KeyAdapter() {
			@Override
			public void keyPressed(KeyEvent e) {
				int action = 0;
				switch (e.getKeyCode()) {
					case KeyEvent.VK_LEFT:
						action = TetrisGame.MOVE_LEFT;
						break;
					case KeyEvent.VK_RIGHT:
						action = TetrisGame.MOVE_RIGHT;
						break;
					case KeyEvent.VK_UP:
						action = TetrisGame.ROTATE_LEFT;
						break;
					case KeyEvent.VK_DOWN:
					case KeyEvent.VK_SPACE:
						action = TetrisGame.MOVE_DOWN;
						break;
				}
				if (action != 0) {
					TetrisView.this.game.processKeyAction(action);
				}
			}
		});
	}

	/*
	 * Реализация LayoutManager 
	 */
	@Override
	public void addLayoutComponent(String name, Component comp) {}

	@Override
	public void removeLayoutComponent(Component comp) {}

	@Override
	public Dimension preferredLayoutSize(Container parent) {
		return null;
	}

	@Override
	public Dimension minimumLayoutSize(Container parent) {
		return null;
	}

	@Override
	public void layoutContainer(Container parent) {
		if (view != null) {
			Insets parentInsets = parent.getInsets();
			Insets viewInsets = view.getInsets();
			Dimension dim = new Dimension(
			parent.getWidth() - parentInsets.left - parentInsets.right - viewInsets.left - viewInsets.right - 1,
			parent.getHeight() - parentInsets.top - parentInsets.bottom - viewInsets.top - viewInsets.bottom - 1);
			cellSize = Math.max(Math.min(dim.width / game.getBoard().getWidth() - 1, dim.height / game.getBoard().getHeight() - 1), 8);
			int width = (cellSize + 1) * game.getBoard().getWidth() + 1 + viewInsets.left + viewInsets.right;
			int height = (cellSize + 1) * game.getBoard().getHeight() + 1 + viewInsets.top + viewInsets.bottom;
			int x = (parent.getWidth() - parentInsets.left - parentInsets.right - width) / 2 + parentInsets.left;
			int y = Math.max((parent.getHeight() - parentInsets.top - parentInsets.bottom - height) / 2 + parentInsets.top, parentInsets.top);
			if (view.getWidth() != width || view.getHeight() != height) {
				view.setBounds(x, y, width, height);
			} else {
				view.setLocation(x, y);
			}
		}
	}

	/**
	 * Реализация компонента "стакан".
	 * 
	 * @author Alexei Tereschenko <aytereschenko@gmail.com>
	 */
	class TetrisComponent extends JComponent {

		public TetrisComponent() {
			setBorder(BorderFactory.createBevelBorder(BevelBorder.LOWERED));
		}

		@Override
		public void setBounds(int x, int y, int width, int height) {
			super.setBounds(x, y, width, height);
		}

		@Override
		protected void paintComponent(Graphics gg) {
			super.paintComponent(gg);
			synchronized (game) {
				int fpos = game.getFigurePos().x;
				int fmin = fpos;
				int fmax = fpos;
				Cell[] cells = game.getFigure().getCells();
				for (int i = 0; i < cells.length; i++) {
					fmin = Math.min(fmin, cells[i].x + fpos);
					fmax = Math.max(fmax, cells[i].x + fpos);
				}

				Graphics2D g = (Graphics2D) gg;
				Insets insets = getInsets();
				int width = getWidth() - insets.left - insets.right;
				int height = getHeight() - insets.top - insets.bottom;
				g.translate(insets.left, insets.top);
//				g.setColor(Color.BLACK);
//				g.fillRect(0, 0, width, height);
				g.setColor(Color.DARK_GRAY);
				for (int x = 0; x <= game.getBoard().getWidth(); x++) {
					g.drawLine(x * (cellSize + 1), 0, x * (cellSize + 1), height);
				}
				for (int y = 0; y <= game.getBoard().getHeight(); y++) {
					g.drawLine(0, y * (cellSize + 1), width, y * (cellSize + 1));
				}

				for (int y = 0; y < game.getBoard().getHeight(); y++) {
					for (int x = 0; x < game.getBoard().getWidth(); x++) {
						int c = game.getBoard().getCell(x, y);
						if (c > 0) {
							g.setColor(colors[c]);
							g.fillRect(x * (cellSize + 1) + 1, y * (cellSize + 1) + 1, cellSize, cellSize);
							paintCellBorder(g, x * (cellSize + 1) + 1, y * (cellSize + 1) + 1, cellSize, cellSize, cellSize / 8);
						} else {
							g.setColor(x >= fmin && x <= fmax ? bgHL : Color.BLACK);
							g.fillRect(x * (cellSize + 1) + 1, y * (cellSize + 1) + 1, cellSize, cellSize);
						}
					}
				}
				g.translate(-insets.left, -insets.top);
			}
		}

		private void paintCellBorder(Graphics2D g, int x, int y, int width, int height, int depth) {
			g.setColor(new Color(255, 255, 255, 128));
			for (int i = 0; i < depth; i++) {
				g.drawLine(x + i, y + i, x + i, y + height - 1 - i);
				g.drawLine(x + 1 + i, y + i, x + width - 1 - i, y + i);
			}
			g.setColor(new Color(0, 0, 0, 128));
			for (int i = 0; i < depth; i++) {
				g.drawLine(x + width - 1 - i, y + 1 + i, x + width - 1 - i, y + height - 2 - i);
				g.drawLine(x + 1 + i, y + height - 1 - i, x + width - 1 - i, y + height - 1 - i);
			}
		}

	}

	/**
	 * Реализация панели с подсчетом очков.
	 * 
	 * @author Alexei Tereschenko <aytereschenko@gmail.com>
	 */
	class TetrisScorePanel extends JPanel {

		private JLabel	lblScore	= new JLabel();
		private JLabel	lblLines	= new JLabel();
		private JLabel	lblLevel	= new JLabel();

		public TetrisScorePanel() {
			JPanel p = new JPanel();
			p.setLayout(new BoxLayout(p, BoxLayout.Y_AXIS));
			p.add(lblScore);
			p.add(Box.createVerticalStrut(20));
			p.add(lblLines);
			p.add(Box.createVerticalStrut(20));
			p.add(lblLevel);
			p.setBorder(BorderFactory.createEtchedBorder());
			FlowLayout fl = (FlowLayout) getLayout();
			fl.setAlignment(FlowLayout.CENTER);
			//setPreferredSize(new Dimension(100, 1));
			add(p);

			game.addScoreChangeListener(new ScoreChangeListener() {
				@Override
				public void stateChanged(ChangeEvent e) {
					final TetrisGame g = (TetrisGame) e.getSource();
					SwingUtilities.invokeLater(new Runnable() {
						@Override
						public void run() {
							lblScore.setText("Score: " + g.getScore());
							lblLines.setText("Lines: " + g.getRemovedLines());
							lblLevel.setText("Level: " + g.getLevel());
						}
					});
				}
			});
		}

	}

}
